/*	Copyright 2007 - Xavier Baro (xbaro@cvc.uab.cat)

	This file is part of eapmlib.

    Eapmlib is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or any 
	later version.

    Eapmlib is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ADABOOST_H__
#define __ADABOOST_H__

#include "EvolutiveLib.h"
#include "AdditiveClassEnsemble.h"

namespace Evolutive {

	//! Defines the AdaBoost version
	enum EVOLUTIVELIB_API AB_VERSION {AB_DISCRETE,AB_GENTLE};

	class EVOLUTIVELIB_API CABWeakLearner
	{
		//! Methods
	public:
		//! Default constructor		
		CABWeakLearner(void);

		//! Default destructor
		virtual ~CABWeakLearner(void);		
#ifdef USE_OPENCV
		//! Find the weak classifier
		virtual CClassifier* GetWeakClassifier(double *Weights,bool *Mask,int *ClassOutput)=0;

		//! Returns the number of samples in the training set.
		virtual int GetNumSamples(void)=0;

		//! Returns a pointer to the labels
		virtual int* GetLabelsPtr(void)=0;
		
		//! Apply the classifier to the samples set
		virtual void Classify(CClassifier *Classifier,int *Class)=0;
		virtual void Classify(CClassifier *Classifier,double *Class)=0;

		//! Change the well classified negative samples
		virtual void UpdateSamplesSet(CClassifier *Classifier)=0;
								
	protected:
			
#endif //USE_OPENCV
					
		//! Attributes
	protected:		
	
	};	

	class EVOLUTIVELIB_API CAdaBoost
	{
		//! Methods
	public:
		//! Default constructor		
		CAdaBoost(void);

		//! Default destructor
		virtual ~CAdaBoost(void);		

#ifdef USE_OPENCV
		//! Define the max number of iterations
		void SetMaxIters(int NumIters);

		//! Define the version of adaboost
		void SetVersion(AB_VERSION Version);

		//! Assign the weak learner object
		void SetWeakLearner(CABWeakLearner *WeakLearner);

		//! Learn the classifiers ensemble
		CAdditiveClassEnsemble *LearnEnsemble(void);

		//! Adds a new classifier to the ensemble
		void AddClassifier(void);

		//! Reset the ensemble to learn it again from the begining
		void Reset(void);

		//! Set validation percentage
		void SetValidationPercentage(double Percentage);

		//! Returns a pointer to the ensemble and remove the association to the class, so it must be released by the calling object
		CAdditiveClassEnsemble *GetEnsemble(void);

		//! Returns a pointer to the ensemble but do not release the association to the class, so it will be automatically removed.
		CAdditiveClassEnsemble *GetEnsemblePtr(void);

		//! Evaluate the amount of miss classified samples using the learned ensemble
		void GetClassErrors(CClassifier *Classifier,int &TrainNumPos,int &TrainNumNeg,int &TrainPosMissSmp,int &TrainNegMissSmp,int &ValNumPos,int &ValNumNeg,int &ValPosMissSmp,int &ValNegMissSmp);
		
		//! Evaluate the classification error and the balanced classification error for the learned ensemble
		void GetError(double &TrainError,double &TrainBER,double &ValidationError,double &ValidationBER);

		//! Initialize the learner (needed when incremental learnings are performed)
		void Initialize(void);
						
	protected:

		//! Create a random stratified validation set
		void BuildValidationSet(void);

		//! Set the labels of the training samples
		void SetLabels(int NumSamples,int *Labels);
			
#endif //USE_OPENCV		
		//! Attributes
	protected:		
		//! Ensemble of classifiers
		CAdditiveClassEnsemble *m_Ensemble;

		//! Adaboost version
		AB_VERSION m_Version;

		//! Pointer to the weak learner
		CABWeakLearner *m_WeakLearner;

		//! Max number of iterations
		int m_MaxIters;
		
		//! Classification values for the last added classifier
		int *m_NewClassLabels;

		//! Converted labels list
		int *m_Labels;

		//! Weights
		double *m_Weights;

		//! Number of samples in the training set
		int m_NumSamples;

		//! Validation percentage
		double m_ValidationPercentage;

		//! Number of samples in the validation set
		int m_NumValidationSamples;

		//! Index of the validation samples
		int *m_ValidationIdx;

		//! Mask over the training set to do not use the validation samples
		bool *m_SamplesMask;
	};	
}

#endif // __ADABOOST_H__
